﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web.UI;
using System.IO;
using System.Web.UI.WebControls;
using System.Reflection;
using PAT;
using PAT.Web.UI;
using PAT.Web.Data;
using PAT.Entities;

public partial class ascx_FriendlyEntitySeach : System.Web.UI.UserControl
{
    #region Atributos

    private String prefixNameSpaceEntities = "PAT.Entities";
    private FieldCollection _fields;
    private DataControlFieldCollection _columns;


    public event EventHandler AcceptEvent;
    
    #endregion

    #region Propiedades

    /// <summary>
    /// 
    /// </summary>
    public String EntityNameRelated
    {
        get
        {
            if (ViewState["_EntityNameRelated"] != null)
            {
                return (string)ViewState["_EntityNameRelated"];
            }
            else
            {
                return String.Empty;
            }
        }
        set
        {
            ViewState["_EntityNameRelated"] = value;
        }
    }

    /// <summary>
    /// Gets / sets the Fields To Exclude Fields Collection
    /// </summary>
    [
    Browsable(true),
    Description("Set / Gets the Fields To Include In the SearchForm"),
    Category("Misc"),
    DefaultValue(""),
    ]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public FieldCollection FieldsToSearch
    {
        get
        {
            if (_fields == null)
            {
                _fields = new FieldCollection();
            }
            return _fields;
        }
    }

    protected Object DataSourceSalida
    {
        get
        {
            if (ViewState["_DataSourceSalida"] != null)
                return ViewState["_DataSourceSalida"];
            else
                return null;
        }
        set
        {
            ViewState["_DataSourceSalida"] = value;
        }
    }

    public Object ObjectSelected
    {
        get
        {
            if (ViewState["_ObjectSelected"] != null)
                return ViewState["_ObjectSelected"];
            else
                return null;
        }
        set
        {
            ViewState["_ObjectSelected"] = value;
        }
    }

    [
    Browsable(true),
    Description("Set / Gets the Columns To Include In the SearchForm"),
    Category("Misc"),
    DefaultValue(""),
    ]
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public DataControlFieldCollection Columns
    {
        get
        {
            return this._columns;
        }
        set 
        {
            this._columns = value;
        }
    }

    #endregion

    #region Metodos

    private String BuildFiltersForSearch()
    {
        String filterWhere = String.Empty;

        Type enumType = EntityUtil.GetType(string.Format("{0}.{1}Column", this.prefixNameSpaceEntities, this.EntityNameRelated));
        Array c = Enum.GetValues(enumType);
        for (int i = 0; i < c.Length; i++)
        {
            ColumnEnumAttribute cea = EntityHelper.GetAttribute<ColumnEnumAttribute>((Enum)c.GetValue(i));
            Field campoBusqueda = this._fields.Find(delegate(Field e) { return e.Value == cea.Name; });
            if (campoBusqueda != null && ((TextBox)tblControles.FindControl("txtSearch_" + campoBusqueda.Value)).Text != String.Empty)
            {
                if (cea.DbType == System.Data.DbType.AnsiString ||
                    cea.DbType == System.Data.DbType.AnsiStringFixedLength ||
                    cea.DbType == System.Data.DbType.String ||
                    cea.DbType == System.Data.DbType.StringFixedLength ||
                    cea.DbType == System.Data.DbType.VarNumeric)
                { 
                    if(campoBusqueda.Operator.ToLower() == "like")
                        filterWhere += campoBusqueda.Value + " " + campoBusqueda.Operator + " '%" + ((TextBox)tblControles.FindControl("txtSearch_" + campoBusqueda.Value)).Text + "%' AND ";
                    else
                        filterWhere += campoBusqueda.Value + " " + campoBusqueda.Operator + " '" + ((TextBox)tblControles.FindControl("txtSearch_" + campoBusqueda.Value)).Text + "' AND ";
                }
                else
                    filterWhere += campoBusqueda.Value + " " + campoBusqueda.Operator + " " + ((TextBox)tblControles.FindControl("txtSearch_" + campoBusqueda.Value)).Text + " AND ";
            }   
        }
        return (filterWhere != String.Empty ? filterWhere.Substring(0, filterWhere.Length - 4) : filterWhere);
    }

    private Object BuildParametersFilterForSearch()
    {
        // Se genera el Type relacionado al parameter builder relacionado a la entidad
        Type parameterBuilderRelacionado = PAT.Data.DataUtil.GetType(string.Format("PAT.Data.Bases.{0}ParameterBuilder", this.EntityNameRelated));
        // Se genera una instancia del Type relacionado
        Object instanciaParameterBuilder = Activator.CreateInstance(parameterBuilderRelacionado.BaseType);

        Type enumType = EntityUtil.GetType(string.Format("{0}.{1}Column", this.prefixNameSpaceEntities, this.EntityNameRelated));
        Array c = Enum.GetValues(enumType);
        for (int i = 0; i < c.Length; i++)
        {
            ColumnEnumAttribute cea = EntityHelper.GetAttribute<ColumnEnumAttribute>((Enum)c.GetValue(i));
            Field campoBusqueda = this._fields.Find(delegate(Field e) { return e.Value == cea.Name; });
            if (campoBusqueda != null && ((TextBox)tblControles.FindControl("txtSearch_" + campoBusqueda.Value)).Text != String.Empty)
            {
                object[] mParam = new object[] { "AND", cea.Name, ((TextBox)tblControles.FindControl("txtSearch_" + campoBusqueda.Value)).Text };
                // Dependiendo del operador se llama la funcion relacionada dentro del parameterbuilder
                switch (campoBusqueda.Operator.ToLower())
                {
                    case "=":
                        parameterBuilderRelacionado.InvokeMember("AppendEquals", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
                        break;
                    case "!=":
                        parameterBuilderRelacionado.InvokeMember("AppendNotEquals", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
                        break;
                    case "like":
                        parameterBuilderRelacionado.InvokeMember("AppendContains", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
                        break;
                    case "not like":
                        parameterBuilderRelacionado.InvokeMember("AppendNotContains", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
                        break;
                    case ">":
                        parameterBuilderRelacionado.InvokeMember("AppendGreaterThan", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
                        break;
                    case ">=":
                        parameterBuilderRelacionado.InvokeMember("AppendGreaterThanOrEqual", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
                        break;
                    case "<":
                        parameterBuilderRelacionado.InvokeMember("AppendLessThan", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
                        break;
                    case "<=":
                        parameterBuilderRelacionado.InvokeMember("AppendLessThanOrEqual", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
                        break;

                }
                parameterBuilderRelacionado.InvokeMember("AppendContains", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, mParam);
            }
        }
        // Se llama el metodo getparameters
        return parameterBuilderRelacionado.InvokeMember("GetParameters", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaParameterBuilder, null);
    }

    private void BuildColumns()
    {
        this.grdBusqueda.Columns.Clear();
        foreach (DataControlField columna in _columns)
            grdBusqueda.Columns.Add(columna);
    }
    
    private void BuildFilters()
    {
        Type enumType = EntityUtil.GetType(string.Format("{0}.{1}Column", this.prefixNameSpaceEntities, this.EntityNameRelated));
        Array c = Enum.GetValues(enumType);
        for (int i = 0; i < c.Length; i++)
        {
            ColumnEnumAttribute cea = EntityHelper.GetAttribute<ColumnEnumAttribute>((Enum)c.GetValue(i));
            switch (cea.DbType)
            {
                case System.Data.DbType.AnsiString: //Texto
                case System.Data.DbType.AnsiStringFixedLength: //Texto
                case System.Data.DbType.Boolean:
                case System.Data.DbType.Byte: //Entero
                case System.Data.DbType.Currency: //Decimal
                case System.Data.DbType.Date: //Fecha
                case System.Data.DbType.DateTime: //Fecha
                case System.Data.DbType.Decimal: //Decimal
                case System.Data.DbType.Double: //Decimal
                case System.Data.DbType.Int16: //Entero
                case System.Data.DbType.Int32: //Entero
                case System.Data.DbType.Int64: //Entero
                case System.Data.DbType.SByte: //Entero
                case System.Data.DbType.Single: //Entero
                case System.Data.DbType.String: //Texto
                case System.Data.DbType.StringFixedLength: //Texto
                case System.Data.DbType.Time:
                case System.Data.DbType.UInt16: //Entero
                case System.Data.DbType.UInt32: //Entero
                case System.Data.DbType.UInt64: //Entero
                case System.Data.DbType.VarNumeric: //Texto
                case System.Data.DbType.Xml: //Texto
                    Field campoBusqueda = this._fields.Find(delegate(Field e) { return e.Value == cea.Name; });
                    if (campoBusqueda != null)
                    {
                        TableRow tblRow = new TableRow();
                        TableCell tcLabel = new TableCell();
                        TableCell tcControles = new TableCell();
                        tcLabel.Text = campoBusqueda.AlternativeDisplay;
                        TextBox txtValor = new TextBox();
                        txtValor.ID = "txtSearch_"+campoBusqueda.Value;
                        tcControles.Controls.Add(txtValor);
                        // Si es entero se agrega el control adecuado para controlarlo
                        if (cea.DbType == System.Data.DbType.Byte || 
                            cea.DbType == System.Data.DbType.Int16 ||
                            cea.DbType == System.Data.DbType.Int32 ||
                            cea.DbType == System.Data.DbType.Int64 ||
                            cea.DbType == System.Data.DbType.SByte ||
                            cea.DbType == System.Data.DbType.Single ||
                            cea.DbType == System.Data.DbType.UInt16 ||
                            cea.DbType == System.Data.DbType.UInt32 ||
                            cea.DbType == System.Data.DbType.UInt64)
                        {
                            AjaxControlToolkit.FilteredTextBoxExtender filterInteger = new AjaxControlToolkit.FilteredTextBoxExtender();
                            filterInteger.ID = "fltInteger_" + campoBusqueda.Value;
                            filterInteger.TargetControlID = "txtSearch_" + campoBusqueda.Value;
                            filterInteger.FilterType = AjaxControlToolkit.FilterTypes.Numbers;
                            tcControles.Controls.Add(filterInteger);
                        }
                        else if (cea.DbType == System.Data.DbType.Decimal ||
                                cea.DbType == System.Data.DbType.Double ||
                                cea.DbType == System.Data.DbType.Currency)
                        {
                            AjaxControlToolkit.FilteredTextBoxExtender filterDecimal = new AjaxControlToolkit.FilteredTextBoxExtender();
                            filterDecimal.ID = "fltDecimal_" + campoBusqueda.Value;
                            filterDecimal.TargetControlID = "txtSearch_" + campoBusqueda.Value;
                            filterDecimal.FilterType = AjaxControlToolkit.FilterTypes.Numbers;
                            filterDecimal.ValidChars = ".";
                            tcControles.Controls.Add(filterDecimal);
                        }
                        else if (cea.DbType == System.Data.DbType.Date ||
                                cea.DbType == System.Data.DbType.DateTime)
                        {
                            // ImageButton
                            ImageButton btnCalendar = new ImageButton();
                            btnCalendar.ID = "btnCalendar_" + campoBusqueda.Value;
                            btnCalendar.ImageUrl = "~/App_Themes/PAT_Theme/images/calendar.png";
                            tcControles.Controls.Add(btnCalendar);
                            // Calendar Extender
                            AjaxControlToolkit.CalendarExtender filterCalendar = new AjaxControlToolkit.CalendarExtender();
                            filterCalendar.TargetControlID = "txtSearch_" + campoBusqueda.Value;
                            filterCalendar.PopupButtonID = "btnCalendar_" + campoBusqueda.Value;
                            tcControles.Controls.Add(filterCalendar);
                        }
                        tblRow.Cells.Add(tcLabel);
                        tblRow.Cells.Add(tcControles);
                        tblControles.Rows.Add(tblRow);
                    }
                    break;
                default:
                    break;
            }
        }
    }

    private void CleanControls(Boolean cleanObjectSelected)
    {
        foreach (TableRow tr in this.tblControles.Rows)
        {
            foreach(Control ctrl in tr.Cells[1].Controls)
            {
                if (ctrl.GetType() == typeof(TextBox))
                    ((TextBox)ctrl).Text = String.Empty;
            }
        }
        this.DataSourceSalida = null;
        if(cleanObjectSelected)
            this.ObjectSelected = null;
        this.grdBusqueda.DataSource = null;
        this.grdBusqueda.DataBind();
    }

    #endregion

    #region Eventos

    protected void Page_Load(object sender, EventArgs e)
    {
        this.BuildFilters();
        if(!IsPostBack)
            this.BuildColumns();
    }

    protected virtual void OnAcceptEvent(EventArgs e)
    {
        if (AcceptEvent != null)
            AcceptEvent(this, e);
    }

    protected void btnBuscar_Click(object sender, EventArgs e)
    {
        object filtros = this.BuildParametersFilterForSearch();

        Type servicioRelacionado = PAT.Services.ServiceUtil.GetType(string.Format("PAT.Services.{0}Service", this.EntityNameRelated));
        object instanciaServicio = Activator.CreateInstance(servicioRelacionado);
        object[] mParam = new object[] { filtros };

        this.DataSourceSalida = servicioRelacionado.InvokeMember("Find", BindingFlags.InvokeMethod, Type.DefaultBinder, instanciaServicio, mParam);
        grdBusqueda.DataSource = this.DataSourceSalida;
        grdBusqueda.DataBind();
    }

    protected void btnLimpiar_Click(object sender, EventArgs e)
    {
        CleanControls(true);
    }

    protected void grdBusqueda_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        try
        {
            this.ObjectSelected = this.DataSourceSalida.GetType().GetMethod("get_Item").Invoke(this.DataSourceSalida, new object[] { Convert.ToInt32(e.CommandArgument) });
        }
        catch (Exception ex)
        {
            this.ObjectSelected = null;
        }
        finally
        {
            CleanControls(false);
            if (AcceptEvent != null)
                AcceptEvent(this, e);
        }
    }

    #endregion
}
